package com.beijiteshop.libcommon.network.ext

import androidx.annotation.Keep
import com.beijiteshop.libcommon.login.LoginHelper
import com.beijiteshop.libcommon.network.model.DataResult
import com.blankj.utilcode.util.LogUtils
import retrofit2.Call
import retrofit2.await
import kotlin.contracts.ExperimentalContracts

/**
 * @Author LiaoZhongKai
 * @Date 2021/3/1 15:01
 * @Description 返回的数据实体基类扩展方法
 */
@Keep
data class BaseRsp<T>(val code: Int, val data: T?, val msg: String?){
    companion object{

        /**
         * 成功状态码
         */
        const val SERVER_CODE_SUCCESS = 1000

        const val TOKEN_INVALID = 401
    }
}

@Keep
data class ResultRsp(val code: Int,val msg:String?,val data: Any?)

/**
 * 扩展retrofit的返回数据，调用await，并catch超时等异常
 * @return DataResult
 */
suspend fun <T : Any> Call<T>.serverData(): DataResult<T> {
    var result: DataResult<T> = DataResult.Loading
    kotlin.runCatching {
        this.await()
    }.onFailure {
        result = DataResult.Error(Exception(ExceptionHandler.getErrorMessage(it)))
        LogUtils.dTag("TAG","error:${it.message}")
        it.printStackTrace()
    }.onSuccess {
        result = DataResult.Success(it)
    }
    return result
}


/**
 * 接口成功，但是业务返回code是成功的情况
 */
@OptIn(ExperimentalContracts::class)
inline fun <T> BaseRsp<T>.onBizError(crossinline block: (code: Int, message: String) -> Unit): BaseRsp<T> {
    kotlin.contracts.contract {
        callsInPlace(block, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
    }
    if (code != BaseRsp.SERVER_CODE_SUCCESS) {
        block.invoke(code, msg ?: "error")
    }
    if (code == BaseRsp.TOKEN_INVALID){
        LoginHelper.toLogin()
    }
    return this
}

/**
 * 接口成功且业务成功 && data != null的情况
 */
@OptIn(ExperimentalContracts::class)
inline fun <reified T> BaseRsp<T>.onBizOK(crossinline action: (code: Int, data: T?, message: String?) -> Unit): BaseRsp<T> {
    kotlin.contracts.contract {
        callsInPlace(action, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
    }
    if (code == BaseRsp.SERVER_CODE_SUCCESS && data != null) {
        action.invoke(code, this.data, msg)
    }
    return this
}

/**
 * 接口成功且业务成功 && data == null的情况
 */
@OptIn(ExperimentalContracts::class)
inline fun <reified T> BaseRsp<T>.onBizEmpty(crossinline action: (msg: String?) -> Unit): BaseRsp<T> {
    kotlin.contracts.contract {
        callsInPlace(action, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
    }
    if (code == BaseRsp.SERVER_CODE_SUCCESS && data == null) {
        action.invoke(msg)
    }
    return this
}

//====================================================

/**
 * 接口业务响应成功
 */
@OptIn(ExperimentalContracts::class)
inline fun ResultRsp.onBizOk(crossinline action: (msg: String?,data: Any?) -> Unit): ResultRsp{
    kotlin.contracts.contract {
        callsInPlace(action, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
    }
    if (code == BaseRsp.SERVER_CODE_SUCCESS) {
        action.invoke(msg,data)
    }
    return this
}

/**
 * 接口业务响应失败
 */
@OptIn(ExperimentalContracts::class)
inline fun ResultRsp.onBizError(crossinline action: (code: Int,msg: String?) -> Unit): ResultRsp{
    kotlin.contracts.contract {
        callsInPlace(action, kotlin.contracts.InvocationKind.EXACTLY_ONCE)
    }
    if (code != BaseRsp.SERVER_CODE_SUCCESS) {
        action.invoke(code,msg)
    }
    if (code == BaseRsp.TOKEN_INVALID){
        LoginHelper.toLogin()
    }
    return this
}

